package com.linkgie.galaxyframework.crypto.context;

import com.linkgie.galaxyframework.crypto.Algorithm;
import com.linkgie.galaxyframework.crypto.PrivateKey;
import com.linkgie.galaxyframework.crypto.PublicKey;
import com.linkgie.galaxyframework.crypto.Signature;
import com.linkgie.galaxyframework.crypto.SignatureService;
import com.linkgie.galaxyframework.crypto.Signer;
import com.linkgie.galaxyframework.crypto.Verifier;
import com.linkgie.galaxyframework.crypto.spi.DigestGenerator;
import com.linkgie.galaxyframework.crypto.spi.PrivateKeybytes;
import com.linkgie.galaxyframework.crypto.spi.PublicKeybytes;
import com.linkgie.galaxyframework.crypto.spi.SignatureFuncSPI;
import com.linkgie.galaxyframework.crypto.spi.Signaturebytes;

public class SignatureServiceImpl extends AsymmetricServiceBase<SignatureFuncSPI> implements SignatureService {

	public SignatureServiceImpl(SignatureFuncSPI innerService) {
		super(innerService);
	}

	@Override
	public Signature sign(PrivateKey privKey, byte[] data) {
		PrivateKeybytes privKeybytes = ENCODING.decode(privKey);
		Signaturebytes signaturebytes = INNSER_SERVICE.sign(privKeybytes, data);
		return ENCODING.encode(ALGORITHM, signaturebytes);
	}

	@Override
	public Signature sign(PrivateKey privKey, byte[] data, int offset, int length) {
		PrivateKeybytes privKeybytes = ENCODING.decode(privKey);
		Signaturebytes signaturebytes = INNSER_SERVICE.sign(privKeybytes, data, offset, length);
		return ENCODING.encode(ALGORITHM, signaturebytes);
	}
	
	@Override
	public byte[] sign(byte[] rawPrivKey, byte[] data) {
		return INNSER_SERVICE.sign(rawPrivKey, data);
	}
	
	@Override
	public byte[] sign(byte[] rawPrivKey, byte[] data, int offset, int length) {
		return INNSER_SERVICE.sign(rawPrivKey, data, offset, length);
	}

	@Override
	public boolean verify(Signature signature, PublicKey pubKey, byte[] data) {
		PublicKeybytes pubKeybytes = ENCODING.decode(pubKey);
		Signaturebytes signaturebytes = ENCODING.decode(signature);
		return INNSER_SERVICE.verify(signaturebytes, pubKeybytes, data);
	}

	@Override
	public boolean verify(Signature signature, PublicKey pubKey, byte[] data, int offset, int length) {
		PublicKeybytes pubKeybytes = ENCODING.decode(pubKey);
		Signaturebytes signaturebytes = ENCODING.decode(signature);
		return INNSER_SERVICE.verify(signaturebytes, pubKeybytes, data, offset, length);
	}
	
	@Override
	public boolean verify(byte[] rawSignature, byte[] rawPubKey, byte[] data) {
		return INNSER_SERVICE.verify(rawSignature, rawPubKey, data);
	}
	
	@Override
	public boolean verify(byte[] rawSignature, byte[] rawPubKey, byte[] data, int offset, int length) {
		return INNSER_SERVICE.verify(rawSignature, rawPubKey, data, offset, length);
	}

	@Override
	public Signer createSigner(PrivateKey privKey) {
		PrivateKeybytes privKeybytes = ENCODING.decode(privKey);
		return new SignatureAdaptor(ALGORITHM, INNSER_SERVICE.createSigner(privKeybytes));
	}
	

	@Override
	public Verifier createVerifier(Signature signature, PublicKey pubKey) {
		PublicKeybytes pubKeybytes = ENCODING.decode(pubKey);
		Signaturebytes signaturebytes = ENCODING.decode(signature);
		
		DigestGenerator<Boolean> verifier = INNSER_SERVICE.createVerifier(signaturebytes, pubKeybytes);
		return new VerifierAdaptor(ALGORITHM, verifier);
	}

	private class SignatureAdaptor extends AbstractDigesterAdaptor<Signaturebytes, Signature> implements Signer {

		public SignatureAdaptor(Algorithm algorithm, DigestGenerator<Signaturebytes> digestGenerator) {
			super(algorithm, digestGenerator);
		}

		@Override
		protected Signature apply(Signaturebytes digest) {
			return ENCODING.encode(ALGORITHM, digest);
		}

	}
	
	private class VerifierAdaptor extends AbstractDigesterAdaptor<Boolean, Boolean> implements Verifier {
		
		public VerifierAdaptor(Algorithm algorithm, DigestGenerator<Boolean> digestGenerator) {
			super(algorithm, digestGenerator);
		}
		
		@Override
		protected Boolean apply(Boolean result) {
			return result;
		}
		
	}

}
